// Module Name: Server.c
//
// Description:
//    This example illustrates a simple TCP server that accepts 
//    incoming client connections. Once a client connection is 
//    established, a thread is spawned to read data from the 
//    client and echo it back (if the echo option is not 
//    disabled).
//
// Compile:
//    cl -o Server Server.c ws2_32.lib
//
// Command line options:
//    server [-p:x] [-i:IP] [-o]
//           -p:x      Port number to listen on
//           -i:str    Interface to listen on
//           -o        Receive only, don't echo the data back
//
#include <winsock2.h>

#include <stdio.h>
#include <stdlib.h>
#include "SafeQueue.h"
#include "AMF3.h"
#include "char_array_buffer.h"
#include "MemoryStream.h"
int    iPort      = 80; // Port to listen for clients on
char   szAddress[128] = "127.0.0.1";       // Interface to listen for clients on
typedef struct SockData{
	int id;
	int length;
	const char* content;
}SockData;
SafeQueue<SockData> msg_queue;
void Trace(SockData& data)
{
	printf("trace\n");
	SockData* sockData = &data;
	if (sockData != NULL)
	{
		printf("sockData.id: %d\n", sockData->id);
		printf("sockData.length: %d\n", sockData->length);
		printf("sockData.content: %s\n", sockData->content);
	}
}
void GotData(int ID,int length,char* content)
{
	SockData sockData;
	sockData.id=ID;
	sockData.length=length;
	sockData.content=content;
	printf("enqueue \n");
	//Trace(sockData);
	msg_queue.enqueue(sockData);
}
void int32ToByte(char* byte,int num)
{
	byte[0] = (num>>24) & 0xFF;
	byte[1] = (num>>16) & 0xFF;
	byte[2] = (num>>8) & 0xFF;
	byte[3] = num & 0xFF;

}
int bytesToInt32(char* b, unsigned length)
{
	int val = 0;
	int j = 0;
	for (int i = length-1; i >= 0; --i)
	{
		val += (b[i] & 0xFF) << (8*j);
		++j;
	}

	return val;
}
int readInt32(Gdk::MemoryStream& stream)
{
	char buff[4];
	int length = 4;
	stream.Read(buff,length);
	return bytesToInt32(buff, length);
}
	DWORD WINAPI RollReceive(LPVOID lpParam)
{
	SOCKET        sock=(SOCKET)lpParam;
	int iResult;
	bool isComplete=true;
	int ID;
	int length;
	int lenReaded;
	int lenLeaved;
	char content[1024];
	bool isPending = false;
	while(true)
	{
		iResult=recv(sock,content,sizeof(int),0);

		Gdk::MemoryStream stream(content,4);
		int value =readInt32(stream);
		printf("len=============%d %d\n",iResult,sizeof(int));
		printf("%d\n",value);
		char byte[4];
		int32ToByte(byte,value);
		if(iResult<=0)
		{
			return 0;
		}
		/*if(isPending)
		{

			iResult=recv(sock,content+lenReaded,lenLeaved,0);
			printf("recv================================================: %d\n", iResult);  
			if(iResult<=0)
			{
				printf("recv failed with error: %d\n", WSAGetLastError());  
				if (content != NULL)
				{
					delete content;
				}
				return 0;
			}
			lenReaded+=iResult;
			lenLeaved=length-lenReaded;
			if (lenLeaved <= 0)
			{
				isPending = false;
				GotData(ID,length,content);
			}
		}
		else
		{
			
			iResult=recv(sock,(char*)&ID,sizeof(int),0);
			if(iResult<=0)
			{
			printf("recv failed with error 0: %d\n", WSAGetLastError());  
			return 0;
			}
			iResult=recv(sock,(char*)&length,sizeof(int),0);
			if(iResult!=sizeof(int))
			{
			printf("recv failed with error 1: %d\n", WSAGetLastError());  
			return 0;
			}
			if (length <= 0)
			{
			return 0;
			}
			isPending = false;
			content = (char *)malloc(sizeof(char) * (length));
			iResult=recv(sock,content,20,0);
			if(iResult<=0)
			{
			if (content != NULL)
			{
			delete content;
			}
			printf("recv failed with error 2: %d\n", WSAGetLastError());  
			return 0;
			}
			lenReaded=iResult;
			lenLeaved=length-lenReaded;
			if (lenLeaved > 0)
			{
			isPending = true;
			}else
			{
			printf("got data \n");  
			GotData(ID,length,content);
			}
		}*/
		
	}
	return 0;
}
DWORD WINAPI QueueReceive(LPVOID lpParam)
{
	while (true)
	{
		SockData data = msg_queue.dequeue();
		Trace(data);
	}
	return 0;
}


//
// Function: main
//
// Description:
//    Main thread of execution. Initialize Winsock, parse the
//    command line arguments, create the listening socket, bind
//    to the local address, and wait for client connections.
//
int main(int argc, char **argv)
{
	WSADATA       wsd;
	SOCKET        sListen,
		sClient;
	int           iAddrSize;
	HANDLE        hThread;
	DWORD         dwThreadId;
	struct sockaddr_in local,client;


	HANDLE        hThread_Queue;
	DWORD         dwThreadId_Queue;

	if (WSAStartup(MAKEWORD(2,2), &wsd) != 0)
	{
		printf("Failed to load Winsock!\n");
		return 1;
	}
	// Create our listening socket
	//
	sListen = socket(AF_INET, SOCK_STREAM, IPPROTO_IP);
	if (sListen == SOCKET_ERROR)
	{
		printf("socket() failed: %d\n", WSAGetLastError());
		return 1;
	}
	local.sin_addr.s_addr = htonl(INADDR_ANY);
	local.sin_family = AF_INET;
	local.sin_port = htons(iPort);

	if (bind(sListen, (struct sockaddr *)&local, 
		sizeof(local)) == SOCKET_ERROR)
	{
		printf("bind() failed: %d\n", WSAGetLastError());
		return 1;
	}
	listen(sListen, 8);

	hThread_Queue = CreateThread(NULL, 0, QueueReceive, 
		NULL, 0, &dwThreadId_Queue);
	if (hThread_Queue == NULL)
	{
		printf("CreateThread() queue failed: %d\n", GetLastError());
	}
	//
	// In a continous loop, wait for incoming clients. Once one 
	// is detected, create a thread and pass the handle off to it.
	//
	while (1)
	{
		iAddrSize = sizeof(client);
		sClient = accept(sListen, (struct sockaddr *)&client,
			&iAddrSize);        
		if (sClient == INVALID_SOCKET)
		{        
			printf("accept() failed: %d\n", WSAGetLastError());
			break;
		}
		printf("Accepted client: %s:%d\n", 
			inet_ntoa(client.sin_addr), ntohs(client.sin_port));

		hThread = CreateThread(NULL, 0, RollReceive, 
			(LPVOID)sClient, 0, &dwThreadId);
		if (hThread == NULL)
		{
			printf("CreateThread() failed: %d\n", GetLastError());
			break;
		}
		
		CloseHandle(hThread);
	}
	CloseHandle(hThread_Queue);
	closesocket(sListen);

	WSACleanup();
	return 0;
}
